﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace xunsearch.lib
{
    public class XSDocument
    {
        private Dictionary<string, Dictionary<string, int>> _terms;
        private Dictionary<string, string> _meta=new Dictionary<string,string>(), _data=new Dictionary<string,string>(), _texts;
        private string _charset = "UTF-8";
        private static int _resSize = 20;

        public XSDocument(Dictionary<string, string> p, string d = "") 
        {
            _data = p;
            if (d != "" && d.Length > 0)
            {
                setCharset(d);
            }
        }
        public XSDocument(string p="", string d = "") 
        {
           
            if (p.Length != _resSize)
            {
                setCharset(p);
                return;
            }
            else
            {
                _meta = unpack(p);
            }
            if (d != "" && d.Length > 0) 
            {
                setCharset(d);
            }
        }

        /// <summary>
        /// 魔术方法 __get
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public string __get(string name) 
        {

            if (_data != null && _data.ContainsKey(name)) 
            {
                return autoConvert(Tool.UnHex(_data[name]));
            }
            return "";
        }

        public void __set(string name, string value) 
        {
            if (_meta != null) {
                throw new Exception("Magick property of result document is read-only");
            }

        }
        /// <summary>
        /// 实现以函数调用访问搜索结果元数据, 支持: docid, rank, percent, weight, ccount
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public string __call(string name) 
        {
            if (_meta != null) {
                name = name.ToLower();
                if (_meta.ContainsKey(name)) 
                {
                    return _meta[name];
                }
            }
            throw new Exception("Call to undefined method");
        }

        /// <summary>
        /// 获取文档字符集
        /// </summary>
        /// <returns></returns>
        public string getCharset() 
        {
            return _charset;
        }
        /// <summary>
        /// 设置文档字符集
        /// </summary>
        /// <param name="charset">设置文档字符集</param>
        public void setCharset(string charset)
        {
            _charset = charset.ToUpper();
            if (_charset == "UTF8")
                _charset = "UTF-8";
        }

        /// <summary>
        /// 获取字段值
        /// </summary>
        /// <returns></returns>
        public Dictionary<string, string> getFields() 
        {
            return _data;
        }

        /// <summary>
        /// 批量设置字段值
        /// </summary>
        /// <param name="data"></param>
        public void setFields(Dictionary<string, string> data) 
        {
            if (data == null)
            {
                _data = new Dictionary<string, string>();
                _meta = new Dictionary<string, string>();
            }
            else
            {
                foreach (var d in data) 
                {
                    if (!_data.ContainsKey(d.Key)) 
                    {
                        _data.Add(d.Key, d.Value);
                    }
                }
            }
        }

        /// <summary>
        /// 设置某个字段的值
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <param name="isMeta"></param>
        public void setField(string name, string value, bool isMeta = false) 
        {
            if (value == "")
            {
                if (isMeta)
                {
                    _meta.Remove(name);
                }
                else
                {
                    _data.Remove(name);
                }
            }
            else {
                if (isMeta)
                {
                    if (_meta.ContainsKey(name))
                    {
                        _meta[name] = value;
                    }
                    else
                    {
                        _meta.Add(name, value);
                    }
                }
                else {
                    if (_data.ContainsKey(name))
                    {
                        _data[name] = value;
                    }
                    else {
                        _data.Add(name, value);
                    }
                }
            }
        }

        /// <summary>
        /// 获取文档字段的值
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public string f(string name) {
            return __get(name);
        }

        /// <summary>
        /// 获取字段的附加索引词列表 (仅限索引文档)
        /// </summary>
        /// <param name="field">字段名称</param>
        /// <returns>索引词列表(词为键, 词重为值), 若无则返回 null</returns>
        public Dictionary<string, int> getAddTerms(string field) 
        {
            if (_terms == null || _terms.ContainsKey(field) == false) 
            {
                return null;
            }
            Dictionary<string, int> terms = new Dictionary<string, int>();
            foreach (var de in _terms[field])
            {
                string term = autoConvert(de.Key);
                terms.Add(de.Key, de.Value);
            }
            return terms;
        }

        /// <summary>
        /// 获取字段的附加索引文本 (仅限索引文档)
        /// </summary>
        /// <param name="field">字段名称</param>
        /// <returns>文本内容, 若无则返回 null</returns>
        public string getAddIndex(string field) 
        {
            if (_texts == null || _texts.ContainsKey(field) == false) 
            {
                return "";
            }
            return autoConvert(_texts[field]);
        }
        
        /// <summary>
        /// 给字段增加索引词 (仅限索引文档)
        /// </summary>
        /// <param name="field">词条所属字段名称</param>
        /// <param name="term">词条内容, 不超过 255字节</param>
        /// <param name="weight">词重, 默认为 1</param>
        public void addTerm(string field, string term, int weight = 1) {
            if (_terms == null) 
            {
                _terms = new Dictionary<string, Dictionary<string, int>>();
            }
            if (_terms.ContainsKey(field) == false)
            {
                Dictionary<string, int> di = new Dictionary<string, int>();
                di.Add(term, weight);
                _terms.Add(field, di);
            }
            else if (_terms[field].ContainsKey(term) == false)
            {
                Dictionary<string, int> di = new Dictionary<string, int>();
                di.Add(term, weight);
                _terms.Add(field, di);
            }
            else {
                _terms[field][term] += weight;
            }
        }

        /// <summary>
        /// 字段增加索引文本 (仅限索引文档)
        /// </summary>
        /// <param name="field">文本所属的字段名称</param>
        /// <param name="text">文本内容</param>
        public void addIndex(string field, string text) 
        {
            if (_texts == null) {
                _texts = new Dictionary<string, string>();
            }
            if (_texts.ContainsKey(field) == false)
            {
                _texts.Add(field, text);
            }
            else {
                _texts[field] += "\n" + text;
            }
        }

        public Dictionary<string, string> getData() 
        {
            return _data;
        }

        /// <summary>
        /// 判断字段是否存在
        /// </summary>
        /// <param name="name">字段名称</param>
        /// <returns>存在返回 true, 若不存在返回 false</returns>
        public bool offsetExists(string name) 
        {
            return _data.ContainsKey(name);
        }

        /// <summary>
        /// 取得字段值, 勿直接调用
        /// </summary>
        /// <param name="name">字段名称</param>
        /// <returns>字段值, 若不存在返回 null</returns>
        public string offsetGet(string name) 
        {
            return __get(name);
        }

        /// <summary>
        /// 设置字段值, 勿直接调用
        /// </summary>
        /// <param name="name">字段名称</param>
        /// <param name="value">字段值</param>
        public void offsetSet(string name, string value) 
        {
            if (string.IsNullOrWhiteSpace(name) == false) 
            {
                __set(name, value);
            }
        }

        /// <summary>
        /// 删除字段值, 勿直接调用
        /// </summary>
        /// <param name="name"></param>
        public void offsetUnset(string name) 
        {
            if (_data != null)
            {
                _data.Remove(name);
            }
        }

        /// <summary>
        /// 文档提交到索引服务器前调用
        /// </summary>
        /// <returns></returns>
        public bool beforeSubmit(XSIndex index) {
            if (_charset == "") 
            {
                _charset = index.xs.getDefaultCharset();
            }
            return true;
        }

        public string autoConvert(string str) 
        {            
            if (_charset == "" || _charset == "UTF-8")
                return str;
            string from = _meta == null ? _charset : "UTF-8";
            string to = _meta == null ? "UTF-8" : _charset;
            return XS.Convert(str, to, from);
        }

        private Dictionary<string, string> unpack(string p) 
        {
            //'Idocid/Irank/Iccount/ipercent/fweight' size=40;
            Dictionary<string, string> di = new Dictionary<string, string>();
            byte[] buf1 = Tool.ToByteArray(p);
            int i=0;
            long docid = (buf1[3 + i] << 23) + (buf1[2 + i] << 15) + (buf1[1 + i] << 7) + buf1[i];
            i = 4;
            long rank = (buf1[3 + i] << 23) + (buf1[2 + i] << 15) + (buf1[1 + i] << 7) + buf1[i];
            i = 8;
            long ccount = (buf1[3 + i] << 23) + (buf1[2 + i] << 15) + (buf1[1 + i] << 7) + buf1[i];
            i = 12;
            int percent = (buf1[3 + i] << 23) + (buf1[2 + i] << 15) + (buf1[1 + i] << 7) + buf1[i];
            i = 16;
            float weight = (buf1[3 + i] << 23) + (buf1[2 + i] << 15) + (buf1[1 + i] << 7) + buf1[i];
            di.Add("docid", docid.ToString());
            di.Add("rank", rank.ToString());
            di.Add("ccount", ccount.ToString());
            di.Add("percent", percent.ToString());
            di.Add("weight", weight.ToString());

            return di;
        }
    }
}
